using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Xml;
using ViewOnAddInsAPI.Helper.Debug;
using ViewOnAddInsAPI.Helper.WPF;
using ViewOnAddInsAPI.Helper.Imaging;
using ViewOnAddInsAPI.Device;
using ViewOnAddInsAPI.HostContract;

#region Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.

/*
 Copyright (c) 2006, 2007, 2008 ViewOn Media Services. All rights reserved.
 This work is copyrighted in its entirety. Permission to use "ViewOn.tv"
 material may be granted only after we receive a written request from you,
 and you receive written permission from us.

 While ViewOn Media Services provides the information herein to anyone,
 we retain copyright on all code, text, graphic images, and other content.
 This means that you may not distribute the code, the text or graphics to others without the
 express written permission of ViewOn Media Services; "mirror" this information on your server
 without our permission; or modify or reuse the code, text or graphics on our servers.
 You may print copies of the information for your own personal use; and, you may reference
 the Service from your own documents. Any commercial use of this material is prohibited without
 the written permission of ViewOn Media Services. In all copies of this information, you must
 retain this notice and any other copyright notices originally included with such information.

 This material may be protected by U.S. and International Copyright laws, and you are legally
 bound by the copyright notices on those systems.

 "ViewOn" logos and other official symbols or graphics may not be used in connection with any
 product or service that has not been expressly authorized in advance in writing or in any manner
 that is likely to cause confusion among the users of this or other Web sites or among the public.
 All other seals, graphics or trademarks of organizations not affiliated with ViewOn Media Services
 that appear on this site are the property of their respective owners.

 ViewOn Media Services reserve all other rights. 
*/

#endregion

#region ViewOn.tv Source Code Licence

/*
This license governs use of the ViewOn.tv software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Summary

The source code is made available to view for reference purposes or to contribute to the project only. Developers may not distribute or modify the code for commercial or non-commercial purposes without express Agreement of View On Media Services.

2. Definitions

The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
"Licensor" means the company "ViewOn Media Services".
"You" means the licensee of the software, who is not engaged in designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software.
"Your company" means the company you worked for when you downloaded the software.
"Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes of debugging and maintaining your products. For clarity, "reference use" does NOT include (a) the right to use the software for purposes of designing, developing, or testing other software, that has the same or substantially the same features or functionality as the software, and (b) the right to distribute the software outside of your company.
"Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor under this license.

3. Grant of Rights

(A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free copyright license to reproduce the software for reference use.
(B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive, worldwide, royalty-free patent license under licensed patents for reference use.
4. Limitations
(A) No Trademark License- This license does not grant you any rights to use the Licensor's name, logo, or trademarks.
(B) If you begin patent litigation against the Licensor over patents that you think may apply to the software (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
(C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
 */

#endregion

namespace ViewOnAddInsAPI.Media
{

    /// <summary>
    /// This class is used to manage and play videos.
    /// </summary>
    sealed public class Video : MediaData
    {

        #region Variables

        static object LOCK = new object();

        private BitmapSource _thumbnail;
        private System.Drawing.Bitmap _thumbnailBitmap;
        private bool _isVideoThumbailLoaded = false;

        //---- Values
        private List<string> _metaTags = new List<string>();
        private List<string> _genres = new List<string>();
        private TimeSpan _duration = TimeSpan.Zero;
        private int _rating = 0;
        private string _director = "";
        private string _plotOutline = "";
        private DateTime _releaseDate = DateTime.MinValue;
        private List<string> _languages = new List<string>();
        private List<string> _traillers = new List<string>();
        private List<string> _companies = new List<string>();
        private List<VideoCast> _casts = new List<VideoCast>();

        #endregion

        #region Constructor

        public Video()
        {
        }

        #endregion

        #region Properties

        public List<string> MetaTags
        {
            get { return _metaTags; }
        }

        public List<string> Languages
        {
            get { return _languages; }
        }

        public List<string> Genres
        {
            get { return _genres; }
        }

        public List<string> Companies
        {
            get { return _companies; }
        }

        public List<VideoCast> Casts
        {
            get { return _casts; }
        }

        public int Rating
        {
            get { return _rating; }
            set
            {
                _rating = value;
                OnPropertyChanged("IsRating1");
                OnPropertyChanged("IsRating2");
                OnPropertyChanged("IsRating3");
                OnPropertyChanged("IsRating4");
                OnPropertyChanged("IsRating5");
            }
        }

        public string Director
        {
            get { return _director; }
            set
            {
                _director = value;
                OnPropertyChanged("Director");
            }
        }

        public string PlotOutline
        {
            get { return _plotOutline; }
            set
            {
                _plotOutline = value;
                OnPropertyChanged("PlotOutline");
            }
        }

        #endregion

        #region Properties : Special

        public string ShortTitle
        {
            get
            {
                if (Title.Length < 17)
                    return Title;

                return Title.Substring(0, 14) + "...";
            }
        }

        public string FormattedDuration
        {
            get
            {
                try
                {
                    return string.Format("{0:00}:{1:00}", (int)_duration.Minutes, (int)_duration.Seconds);
                }
                catch
                {
                    return "- : -";
                }
            }
        }

        public string FormattedReleaseDate
        {
            get
            {
                try
                {
                    return string.Format("{0:00}-{1:00}-{2:00}", (int)_releaseDate.Day, (int)_releaseDate.Month, (int)_releaseDate.Year);
                }
                catch
                {
                    return "- : -";
                }
            }
            set
            {
                if (!DateTime.TryParseExact(value, "d-M-yyyy", System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.None, out _releaseDate))
                    DateTime.TryParseExact(value, "d-M-yy", System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.None, out _releaseDate);
            }
        }

        public string FormattedMetaTags
        {
            get
            {
                return GetFormattedList(_metaTags);
            }
            set
            {
                _metaTags = SetFormattedList(value);
            }
        }

        public string FormattedGenres
        {
            get
            {
                return GetFormattedList(_genres);
            }
            set
            {
                _genres = SetFormattedList(value);
            }
        }

        public string FormattedCasts
        {
            get
            {
                return GetFormattedListVideoCast(_casts);
            }
            set
            {
                _casts = SetFormattedListVideoCast(value);
            }
        }

        public string FormattedCompanies
        {
            get
            {
                return GetFormattedList(_companies);
            }
            set
            {
                _companies = SetFormattedList(value);
            }
        }

        public string FormattedLanguages
        {
            get
            {
                return GetFormattedList(_languages);
            }
            set
            {
                _languages = SetFormattedList(value);
            }
        }

        public string FormattedTraillers
        {
            get
            {
                return GetFormattedList(_traillers);
            }
            set
            {
                _traillers = SetFormattedList(value);
            }
        }

        public bool IsRating1
        {
            get { return (Rating >= 1); }
            set { }
        }

        public bool IsRating2
        {
            get { return (Rating >= 2); }
            set { }
        }

        public bool IsRating3
        {
            get { return (Rating >= 3); }
            set { }
        }

        public bool IsRating4
        {
            get { return (Rating >= 4); }
            set { }
        }

        public bool IsRating5
        {
            get { return (Rating >= 5); }
            set { }
        }

        #endregion

        #region Icon...

        /// <summary>
        /// Returns the video thumbnail
        /// </summary>
        public BitmapSource Thumbnail
        {
            get
            {
                if (_thumbnail == null)
                    if (_thumbnailBitmap != null)
                        _thumbnail = LoadBitmap(_thumbnailBitmap);

                return _thumbnail;
            }
        }

        private void LoadVideoThumbail()
        {
            if (_isVideoThumbailLoaded)
                return;
            _isVideoThumbailLoaded = true;
            Thread thread = new Thread(new ThreadStart(AsyncLoadPreview));
            thread.Priority = ThreadPriority.Lowest;
            thread.Start();
        }

        private void AsyncLoadPreview()
        {
            lock (LOCK)
            {
                _thumbnailBitmap = VideoThumbnailExtractor.GetThumbnail(Path);

                Host.ApplicationWindow.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                                                                        (DelegateInvoker)delegate {
                                                                            //_thumbnail = VideoThumbnailExtractor.GetThumbnail(Path);
                                                                            OnPropertyChanged("Thumbnail");
                                                                        });
            }
        }

        private static BitmapSource LoadBitmap(System.Drawing.Bitmap source)
        {
            return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(source.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        }

        #endregion

        #region Icon...

        override public BitmapImage IconBig
        {
            get
            {
                LoadVideoThumbail();

                if (_thumbnailBitmap == null)
                    return null;

                MemoryStream ms = new MemoryStream();
                _thumbnailBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);

                BitmapImage bImg = new BitmapImage();
                bImg.BeginInit();
                bImg.StreamSource = new MemoryStream(ms.ToArray());
                bImg.EndInit();

                return bImg;
            }
        }

        #endregion

        #region FromFile

        static public Video FromFile(string path)
        {
            Video video = new Video();

            video.Path = path;
            video.Title = new FileInfo(path).Name;
            //try
            //{
            //    TagLib.File tagFile = TagLib.File.Create(path);

            //    music.Title = tagFile.Tag.Title;
            //    if (music.Title == null)
            //        music.Title = "";

            //    if (tagFile.Tag.Performers.Length > 0)
            //        music.Artist = tagFile.Tag.Performers[0];
            //    if (music.Artist == null)
            //        music.Artist = "";

            //    if (tagFile.Tag.Genres.Length > 0)
            //        music.Genre = tagFile.Tag.Genres[0];
            //    if (music.Genre == null)
            //        music.Genre = "";

            //    music.Album = tagFile.Tag.Album;
            //    if (music.Album == null)
            //        music.Album = "";
            //    music.Duration = tagFile.Properties.Duration;

            //    if (tagFile.Tag.Composers.Length > 0)
            //        music.Composer = tagFile.Tag.Composers[0];
            //    if (music.Composer == null)
            //        music.Composer = "";

            //    music.Year = (int)tagFile.Tag.Year;
            //    music.Track = (int)tagFile.Tag.Track;
            //    music.TrackCount = (int)tagFile.Tag.TrackCount;
            //    music.Comment = tagFile.Tag.Comment;
            //    if (music.Comment == null)
            //        music.Comment = "";

            //    TagLib.Id3v2.Tag tagV2 = tagFile.GetTag(TagLib.TagTypes.Id3v2, true) as TagLib.Id3v2.Tag;

            //    //PopularimeterFrame popm = PopularimeterFrame.Get(id3tag, "deutronium@gmx.de", true);
            //    //Console.WriteLine(popm.EncryptionId);
            //    //Console.WriteLine(popm.Flags);
            //    //Console.WriteLine(popm.FrameId);
            //    //Console.WriteLine(popm.GroupId);
            //    //Console.WriteLine(popm.PlayCount);
            //    //Console.WriteLine(popm.Rating);
            //    //Console.WriteLine(popm.Size);
            //    //Console.WriteLine(popm.User);

            //    //---- Rating
            //    if (tagV2 != null)
            //    {
            //        TagLib.Id3v2.PopularimeterFrame popm = TagLib.Id3v2.PopularimeterFrame.Get(tagV2, "deutronium@gmx.de", true);
            //        if (popm != null)
            //        {
            //            if (popm.Rating >= 1 && popm.Rating <= 24)
            //                music.Rating = 1;
            //            else if (popm.Rating >= 25 && popm.Rating <= 49)
            //                music.Rating = 2;
            //            else if (popm.Rating >= 50 && popm.Rating <= 74)
            //                music.Rating = 3;
            //            else if (popm.Rating >= 75 && popm.Rating <= 98)
            //                music.Rating = 4;
            //            else if (popm.Rating == 99)
            //                music.Rating = 5;
            //        }
            //    }
            //}
            //catch (Exception e)
            //{
            //// Default
            //System.IO.FileInfo fileInfo = new System.IO.FileInfo(path);
            //string name = fileInfo.Name;
            //music.Title = name.Substring(0, name.Length - fileInfo.Extension.Length);
            //}

            return video;
        }

        #endregion

        #region ToTagLibFile

        //public TagLib.File ToTagLibFile()
        //{
        //    TagLib.File tagFile = TagLib.File.Create(Path);

        //    tagFile.Tag.Title = Title;
        //    tagFile.Tag.Performers = new string[1] { Artist };
        //    tagFile.Tag.Genres = new string[1] { Genre };
        //    tagFile.Tag.Album = Album;
        //    tagFile.Tag.Composers = new string[1] { Composer };
        //    tagFile.Tag.Year = (uint)Year;
        //    tagFile.Tag.Track = (uint)Track;
        //    tagFile.Tag.TrackCount = (uint)TrackCount;
        //    tagFile.Tag.Comment = Comment;
        //    //tagFile.Properties.Duration = Duration;

        //    TagLib.Id3v2.Tag tagV2 = tagFile.GetTag(TagLib.TagTypes.Id3v2, true) as TagLib.Id3v2.Tag;
        //    if (tagV2 != null)
        //    {
        //        TagLib.Id3v2.PopularimeterFrame popm = TagLib.Id3v2.PopularimeterFrame.Get(tagV2, "deutronium@gmx.de", true);
        //        if (popm != null)
        //        {
        //            if (Rating == 1)
        //                popm.Rating = 1;
        //            else if (Rating == 2)
        //                popm.Rating = 25;
        //            else if (Rating == 3)
        //                popm.Rating = 50;
        //            else if (Rating == 4)
        //                popm.Rating = 75;
        //            else if (Rating == 4)
        //                popm.Rating = 99;
        //        }
        //    }

        //    return tagFile;
        //}

        #endregion

        #region ToXml / FromXml

        override public string XmlTag
        {
            get
            {
                return "Video";
            }
        }

        override public XmlNode ToXml(XmlDocument document)
        {
            string content = "";

            XmlNode subNode;
            XmlNode subNode2;
            XmlAttribute attribute;

            XmlNode node = base.ToXml(document);

            //---- Meta tags
            attribute = document.CreateAttribute("MetaTags");
            attribute.Value = XmlConvert.EncodeLocalName(FormattedMetaTags);
            node.Attributes.Append(attribute);

            //---- Genres
            subNode = node.AppendChild(document.CreateElement("Genres"));
            foreach (string genre in _genres)
            {
                subNode2 = subNode.AppendChild(document.CreateElement("Genre"));
                attribute = subNode2.Attributes.Append(document.CreateAttribute("Value"));
                attribute.Value = XmlConvert.EncodeLocalName(genre);
            }

            //---- Duration
            attribute = node.Attributes.Append(document.CreateAttribute("Duration"));
            attribute.Value = _duration.ToString();

            //---- Rating
            attribute = node.Attributes.Append(document.CreateAttribute("Rate"));
            attribute.Value = _rating.ToString();

            //---- Director
            attribute = node.Attributes.Append(document.CreateAttribute("Director"));
            attribute.Value = XmlConvert.EncodeLocalName(_director);

            //---- Plot Outline
            attribute = node.Attributes.Append(document.CreateAttribute("PlotOutline"));
            attribute.Value = XmlConvert.EncodeLocalName(_plotOutline);

            //---- Release date
            attribute = node.Attributes.Append(document.CreateAttribute("ReleaseDate"));
            attribute.Value = XmlConvert.EncodeLocalName(FormattedReleaseDate);

            //---- LanguagesCodes
            subNode = node.AppendChild(document.CreateElement("LanguagesCodes"));
            foreach (string language in _languages)
            {
                subNode2 = subNode.AppendChild(document.CreateElement("Language"));
                attribute = subNode2.Attributes.Append(document.CreateAttribute("Value"));
                attribute.Value = XmlConvert.EncodeLocalName(language);
            }

            //---- Traillers
            subNode = node.AppendChild(document.CreateElement("Traillers"));
            foreach (string trailler in _traillers)
            {
                subNode2 = subNode.AppendChild(document.CreateElement("Trailler"));
                attribute = subNode2.Attributes.Append(document.CreateAttribute("Value"));
                attribute.Value = XmlConvert.EncodeLocalName(trailler);
            }

            //---- Companies
            subNode = node.AppendChild(document.CreateElement("Companies"));
            foreach (string company in _companies)
            {
                subNode2 = subNode.AppendChild(document.CreateElement("Company"));
                attribute = subNode2.Attributes.Append(document.CreateAttribute("Value"));
                attribute.Value = XmlConvert.EncodeLocalName(company);
            }

            //---- Casts
            subNode = node.AppendChild(document.CreateElement("Casts"));
            foreach (VideoCast cast in _casts)
            {
                subNode2 = subNode.AppendChild(document.CreateElement("Cast"));

                attribute = subNode2.Attributes.Append(document.CreateAttribute("FirstName"));
                attribute.Value = XmlConvert.EncodeLocalName(cast.FirstName);

                attribute = subNode2.Attributes.Append(document.CreateAttribute("LastName"));
                attribute.Value = XmlConvert.EncodeLocalName(cast.LastName);

                attribute = subNode2.Attributes.Append(document.CreateAttribute("Role"));
                attribute.Value = XmlConvert.EncodeLocalName(cast.Role);
            }

            return node;
        }

        public override void FromXml(XmlNode node)
        {
            base.FromXml(node);

            //---- Version 0.3 does not support theses fields.
            if (node.Attributes["MetaTags"] != null)
            {

                //---- Meta tags
                string metaTags = XmlConvert.DecodeName(node.Attributes["MetaTags"].Value);
                _metaTags = SetFormattedList(metaTags);

                //---- Genres
                foreach (XmlNode subNode in node.SelectNodes("Genres/Genre"))
                    _genres.Add(XmlConvert.DecodeName(subNode.Attributes["Value"].Value));

                //---- Duration
                _duration = TimeSpan.Parse(node.Attributes["Duration"].Value);

                //---- Rating
                _rating = Int32.Parse(node.Attributes["Rate"].Value);

                //---- Director
                _director = XmlConvert.DecodeName(node.Attributes["Director"].Value);

                //---- Plot Outline
                _plotOutline = XmlConvert.DecodeName(node.Attributes["PlotOutline"].Value);

                //---- Release date
                FormattedReleaseDate = XmlConvert.DecodeName(node.Attributes["ReleaseDate"].Value);

                //---- LanguagesCodes
                foreach (XmlNode subNode in node.SelectNodes("LanguagesCodes/Language"))
                    _languages.Add(XmlConvert.DecodeName(subNode.Attributes["Value"].Value));

                //---- Traillers
                foreach (XmlNode subNode in node.SelectNodes("Traillers/Trailler"))
                    _traillers.Add(XmlConvert.DecodeName(subNode.Attributes["Value"].Value));

                //---- Companies
                foreach (XmlNode subNode in node.SelectNodes("Companies/Company"))
                    _companies.Add(XmlConvert.DecodeName(subNode.Attributes["Value"].Value));

                //---- Casts
                foreach (XmlNode subNode in node.SelectNodes("Casts/Cast"))
                {
                    VideoCast cast = new VideoCast();
                    cast.FirstName = XmlConvert.DecodeName(subNode.Attributes["FirstName"].Value);
                    cast.LastName = XmlConvert.DecodeName(subNode.Attributes["LastName"].Value);
                    cast.Role = XmlConvert.DecodeName(subNode.Attributes["Role"].Value);
                    _casts.Add(cast);
                }

            }
        }

        #endregion

        #region Get/Set FormattedList

        private string GetFormattedList(List<string> list)
        {
            string result = "";
            foreach (string item in list)
                result += item + ";";

            return result;
        }

        private List<string> SetFormattedList(string formatted)
        {
            List<string> list = new List<string>();
            string[] items = formatted.Split(new char[] { ',', ';' });
            foreach (string item in items)
                if (item.Trim().Length > 0)
                    list.Add(item.Trim());

            return list;
        }

        #endregion

        #region Get/Set FormattedListVideoCast

        private string GetFormattedListVideoCast(List<VideoCast> list)
        {
            string result = "";
            foreach (VideoCast item in list)
                result += item.FirstName + " " + item.LastName + "; ";

            return result;
        }

        private List<VideoCast> SetFormattedListVideoCast(string formatted)
        {
            List<VideoCast> list = new List<VideoCast>();
            string[] items = formatted.Split(new char[] { ',', ';' });
            foreach (string item in items)
            {
                if (item.Trim().Length < 1)
                    continue;
                string[] nameItems = item.Trim().Split(new char[] { ' ' });
                if (nameItems.Length > 0)
                {
                    VideoCast cast = new VideoCast();
                    cast.FirstName = nameItems[0];
                    if (nameItems.Length > 1)
                        cast.LastName = nameItems[1];

                    list.Add(cast);
                }
            }

            return list;
        }

        #endregion

    }

    #region VideoCast

    /// <summary>
    /// Represent a video's cast.
    /// </summary>
    sealed public class VideoCast
    {
        public string FirstName;
        public string LastName;
        public string Role;
    }

    #endregion

    #region VideoFeatureItemComparer

    /// <summary>
    /// This class allows to compare several videos.
    /// </summary>
    sealed public class VideoFeatureItemComparer : IComparer<MediaData>
    {

        #region IComparer<MediaData> Members

        public int Compare(MediaData x, MediaData y)
        {
            if (x is MediaFolder && y is Video)
                return -1;

            if (x is Video && y is MediaFolder)
                return 1;

            return x.Title.CompareTo(y.Title);
        }

        #endregion

    }

    #endregion

}
